#include "stdafx.h"

#include <MyControls/App.h>
#include <MyControls/TransformEditor.h>
#include <MyControls/Resource.h>
#include <mtx/fixed.h>
#include <mtx/algorithm.h>

namespace My { 

BEGIN_MESSAGE_MAP(TransformEditor, CCmdTarget)
END_MESSAGE_MAP()

// TransformEditor

TransformEditor::TransformEditor(ZoomBench & bench) :
	m_Bench(bench), 
	m_TransformTool(* this),
	m_pOwner(0)
{
	m_pTool = &m_TransformTool;
}
	
TransformEditor::~TransformEditor()
{
	assert(!IsOpen());
}

ZoomBench & TransformEditor::GetBench()
{
	return m_Bench;
}

TransformOwner * TransformEditor::GetTransformOwner() const
{
	return m_pOwner;
}

bool TransformEditor::IsOpen() const
{
	return m_pOwner != 0;
}
		
void TransformEditor::Open(TransformOwner & owner)
{
	if (IsOpen())
		Close();
	m_pOwner = &owner;
	UpdateTransform();
	DispatchEvent(StateChange(* this));
	m_Bench.SetActiveTool(m_pTool);
}

void TransformEditor::Close()
{
	if (!IsOpen())
		return;
	m_pTool = m_Bench.GetActiveTool();
	m_Bench.SetActiveTool(0);
	m_pOwner = 0;
	DispatchEvent(StateChange(* this));
}

void TransformEditor::PaintRect(CDC * pDC, const CRect & rClip)
{
	if (!IsOpen())
		return;
	LOGBRUSH lb;
	lb.lbColor = RGB(255, 255, 0);
	lb.lbStyle = BS_SOLID;
	lb.lbHatch = 0;
	CPen pYellow(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, 0);
	CPen pGreen(PS_SOLID, 1, RGB(0, 255, 0));

	// Draw composition margins
	CPen * pOldPen = pDC->SelectObject(&pYellow);
	{
		rect<double> rMargins = m_pOwner->GetMargins();
		CPoint p0, p1;
		p0 = m_Bench.BenchToClient(point<float>(rMargins.x1, rMargins.y1));
		p1 = m_Bench.BenchToClient(point<float>(rMargins.x2, rMargins.y2));

		pDC->MoveTo(p0.x, p1.y + 10);
		pDC->LineTo(p0.x, p0.y - 11);
		pDC->MoveTo(p0.x - 10, p0.y);
		pDC->LineTo(p1.x + 11, p0.y);
		pDC->MoveTo(p1.x, p0.y - 10);
		pDC->LineTo(p1.x, p1.y + 11);
		pDC->MoveTo(p1.x + 10, p1.y);
		pDC->LineTo(p0.x - 11, p1.y);
	}

	pDC->SelectObject(&pGreen);
	rect<double> rBounds = m_pOwner->GetBounds();
	point<double> imageCorners[4] = {
		point<double>(rBounds.x1, rBounds.y2),
		point<double>(rBounds.x1, rBounds.y1),
		point<double>(rBounds.x2, rBounds.y1),
		point<double>(rBounds.x2, rBounds.y2)	
	};
	CPoint pp[5];
	const Affine & t = m_Transform;
	int i;
	for (i = 0; i < 4; ++i)
		pp[i] = m_Bench.BenchToClient(point<float>(t(imageCorners[i])));
	pp[4] = pp[0];
	pDC->Polyline(pp, 5);

	CBrush hollow; hollow.CreateStockObject(HOLLOW_BRUSH);
	CBrush fill(RGB(0, 255, 0));
	CBrush * pOldBrush = pDC->SelectObject(&fill);
	// Draw corners
	for (i = 0; i < 3; ++i)
	{
		CRect r(pp[i], pp[i]);
		r.InflateRect(3, 3, 4, 4);
		pDC->Rectangle(&r);
	}
	pDC->SelectObject(&hollow);
	{
		CRect r(pp[3], pp[3]);
		r.InflateRect(3, 3, 4, 4);
		pDC->Rectangle(&r);
	}

	// Draw anchor
	point<double> imageCenter((rBounds.x1 + rBounds.x2) / 2, (rBounds.y1 + rBounds.y2) / 2);
	CPoint p = m_Bench.BenchToClient(point<float>(t(imageCenter)));
	CRect r(p, p);
	r.InflateRect(4, 4, 5, 5);
	pDC->Ellipse(&r);
	pDC->MoveTo(p.x, p.y);
	pDC->LineTo(p.x + 1, p.y);
	pDC->MoveTo(p.x - 5, p.y);
	pDC->LineTo(p.x - 8, p.y);
	pDC->MoveTo(p.x + 5, p.y);
	pDC->LineTo(p.x + 8, p.y);
	pDC->MoveTo(p.x, p.y - 5);
	pDC->LineTo(p.x, p.y - 8);
	pDC->MoveTo(p.x, p.y + 5);
	pDC->LineTo(p.x, p.y + 8);

	pDC->SelectObject(pOldPen);
	pDC->SelectObject(pOldBrush);

	//pDC->SetROP2(oldROP);
}

void TransformEditor::SetTransform(const Affine & t)
{
	if (t != m_Transform)
	{
		m_Transform = t;
		m_Bench.InvalidateBench();
		m_Bench.InvalidateBorder();
	}
}

void TransformEditor::CalcTransform(const point<double> p[3], const point<double> q[3])
{
	mtx::fixed<6, 6>::matrix A(0);
	mtx::fixed<6>::vector b;
	int j = 0;
	for (int i = 0; i < 3; ++i) {
		A(j, 0) = p[i].x;
		A(j, 1) = p[i].y;
		A(j, 4) = 1;
		b(j) = q[i].x;
		++j;
		A(j, 2) = p[i].x;
		A(j, 3) = p[i].y;
		A(j, 5) = 1;
		b(j) = q[i].y;
		++j;
	}
	mtx::sle(A, b);
	Affine t;
	t.xx = b(0);
	t.xy = b(1);
	t.yx = b(2);
	t.yy = b(3);
	t.x = b(4);
	t.y = b(5);
	SetTransform(t);
}

void TransformEditor::Synchronize()
{
	if (!IsOpen())
		return;
	GetTransformOwner()->SetTransform(GetTransform());
}

void TransformEditor::UpdateTransform()
{
	if (!IsOpen())
		return;
	SetTransform(GetTransformOwner()->GetTransform());
}

/*
void TransformEditor::OnToolBrush()
{
	if (!IsOpen())
		return;
	m_Bench.SetActiveTool(Brush());
}

void TransformEditor::OnUpdateToolBrush(CCmdUI * pCmdUI)
{
	pCmdUI->SetCheck(m_Bench.GetActiveTool() == Brush());
	pCmdUI->Enable(IsOpen() ? 1 : 0);
}

void MaskEditor::OnToolFill()
{
	if (!IsOpen())
		return;
	m_Bench.SetActiveTool(Fill());
}

void MaskEditor::OnUpdateToolFill(CCmdUI * pCmdUI)
{
	pCmdUI->SetCheck(m_Bench.GetActiveTool() == Fill());
	pCmdUI->Enable(IsOpen() ? 1 : 0);
}
*/

} // My